#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <strings.h>

int size =  sizeof(struct sockaddr_in);
int conect_sk;
int connect_addr[10]; //创建一个数组来存放返回的新的已连接套接字
int i  = 0;

//线程发送信息回调函数
void * func(void * arg)
{
    char * J_senmsg = calloc(1,128);
    int p;
    while(1)
    {
        printf("请输入#查看在线好友套接字\n");
        while(getchar() != '#');
        printf("****************在线好友如下***********************\n");

        for(int num = 0;num < i;num++)
        {
            printf("connect_addr[%d] = %d\n",num,connect_addr[num]);
        }
        printf("*************************************************\n");
        printf("请选择要回复的好友套借字：\n");
        scanf("%d",&p);
        while(getchar() != '\n');

        printf("Jacy 请输入要回复的信息：\n");
        fgets(J_senmsg, 128 , stdin );

        int ret =  send(connect_addr[p], J_senmsg , strlen(J_senmsg), 0 );
        if(ret == -1)
        {
            perror("jack发送失败\n");
            break;
        }
        else
        {
            printf("jack成功发送信息给%d:%s\n",connect_addr[p],J_senmsg);
        }
    }
    
    
}


//线程接受信息回调函数
void * revmsg(void * arg)
{
    int  connect_fd = *(int *)arg;  //参数类型进行转换

     //坐等对方电话打来
    char * rev_msg = calloc(1,128);
    while(1)
    {   
        bzero(rev_msg,128);
        printf("等待Rose发来消息...\n");

        int ret = recv(connect_fd , rev_msg, 128 , 0);

        if(ret == -1)
        {
            perror("recive faile\n");
            break;
        }
        else
        {
            printf("recive byte form %d :%d msg:%s\n",connect_fd, ret , rev_msg);
        }

    }

}


int main(int argc, char const *argv[])
{
    
    //购买手机（创建网络编程接口）
    int sockfd = socket( AF_INET, SOCK_STREAM , 0);
    if(sockfd == -1)
    {
        perror("socket  faile\n");
        return -1;
    }
    
    //买电话卡（个人IP以及端口号的设置）

    // struct sockaddr_in {
    // sa_family_t     sin_family;     /* AF_INET */
    // in_port_t       sin_port;       /* Port number */
    // struct in_addr  sin_addr;       /* IPv4 address */
    // };
    struct sockaddr_in my_addr = {0};
    my_addr.sin_family = AF_INET;
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY); //谁来接收都可以
    my_addr.sin_port = htons(65001);


    //绑定手机和电话卡
    int ret = bind(sockfd, (struct sockaddr *)&my_addr,size); //如果成功则返回一个新的待连接字
    if(ret == -1)
    {
        perror("bind faile\n");
        return -1;
    }
    else
    {
        printf("绑定成功\n");
    }


    //设置监听
    if(listen(sockfd, 4))
    {
        perror("listen faile\n");
        return -1;
    }
    else
    {
        printf("监听成功\n");
    }
    
    //创建一个线程用来发送信息
    pthread_t thread; 
    int m = pthread_create(&thread, NULL , func , NULL);
    if(m)
    {
        perror("ptread error\n");
    }
    else
    {
        printf("发送信息线程创建成功\n");
    }

    //一直等待连接，只要有人连接就将一个已连接套借字存放到数组里面并创建一个新线程，因为accept函数会阻塞，没办法像UDP那样只需要一个线程，需要多个线程进行接受
    struct sockaddr_in from_addr;
    while(1)
    {
        conect_sk =  accept(sockfd , (struct sockaddr *)&from_addr,&size);  //如果成功就返回一个新的已连接字,会阻塞等待，如果没有人连接就会一直等待，程序会一直卡在这里
        if(conect_sk == -1)
        {
            perror("conect faile\n");
            return -1;
        }
        else
        {
            printf("连接成功%d \n",conect_sk);
            connect_addr[i]= conect_sk;//来一个就存放一个已连接套借字->为了后续选择向谁发送信息用
            int m = pthread_create(&thread, NULL , revmsg , (void *)&connect_addr[i]);//然后创建一个线程，只不过它们同时使用一个参数不同的回调函数
            if(m)
            {
                perror("ptread error\n");
            }
            else
            {
                printf("接受信息线程%d创建成功\n",connect_addr[i]);
                i++;
            }
            if(i > 9)  //超过数组存放最大值则跳出循环，不再等待接受
            {
                break;
            }
        }

    }

    while(1);//如果没有这条指令：break之后会跳出主循环，程序将结束；



    //关闭套接字
    close(sockfd);

    return 0;
}
